#include "syntax_parser.h"
#include "errors_warnings.h"

#include "main_container.h"
extern MainContainer * CompilerData;


// <name> ~ NAME <name_add>  {NAME}
void Parser::Parse_Name(SyntaxTreeNode * parent)
{
#ifdef TRACE
    CompilerData->LogTrace->ReportEntry("Parse_Name");
#endif

	LexicUnit currentUnit;
	// get current lexic unit
#ifdef TRACE
	CompilerData->LogTrace->ReportLine("Getting lexic unit.");
#endif
	currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);

	if(currentUnit.type == LUTypeIdentifier)
	{
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized \"NAME\"");
#endif
		// write type of production in this node
		parent->Production = Gr_Name__NAME_NameAdd;

		// process terminal symbol 'NAME' 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		newNode0->LexUnitID=this->CurrentLexicPosition;
		newNode0->Production=Gr_Terminal;
		//increase counter
		CurrentLexicPosition++;

		// process nonterminal symbol <name_add> 
		SyntaxTreeNode * newNode1 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode1);
		Parse_NameAdd(newNode1);

	}


	else
	{
#ifdef TRACE
	        CompilerData->LogTrace->ReportLine("Error.");
#endif
		// ERROR has been found
		// REPORT ERROR
		CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_CLASS_BODY_MATCH);
		// MAKE LOGICAL RECOVERING
	}
#ifdef TRACE
		CompilerData->LogTrace->ReportExit("Parse_Name");
#endif
}

/*
This method is added just for <variable_value>
*/
// <name_ambiguous> ~ NAME <name_add_ambiguous>  {NAME}
void Parser::Parse_Name_Ambiguous(SyntaxTreeNode * parent)
{
#ifdef TRACE
    CompilerData->LogTrace->ReportEntry("Parse_Name_Ambiguous");
#endif

	LexicUnit currentUnit;
	// get current lexic unit
#ifdef TRACE
	CompilerData->LogTrace->ReportLine("Getting lexic unit.");
#endif
	currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);

	if(currentUnit.type == LUTypeIdentifier)
	{
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized \"NAME\"");
#endif
		// write type of production in this node
		parent->Production = Gr_NameAmbiguous__NAME_NameAddAmbiguous;

		// process terminal symbol 'NAME' 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		newNode0->LexUnitID=this->CurrentLexicPosition;
		newNode0->Production=Gr_Terminal;
		//increase counter
		CurrentLexicPosition++;

		// process nonterminal symbol <name_add_ambiguous> 
		SyntaxTreeNode * newNode1 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode1);
		Parse_NameAdd_Ambiguous(newNode1);

	}


	else
	{
#ifdef TRACE
	        CompilerData->LogTrace->ReportLine("Error.");
#endif
		// ERROR has been found
		// REPORT ERROR
		CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_CLASS_BODY_MATCH);
		// MAKE LOGICAL RECOVERING
	}
#ifdef TRACE
		CompilerData->LogTrace->ReportExit("Parse_Name_Ambiguous");
#endif
}


// <name_add> ~ <name_period_add> <name_add>  {.}
// <name_add> ~ ? {;, as, {, <, (, :, ,, [, instance, ), NAME, after, every, send, while, until, ^, *, /, %, +, -, >, <=, >=, ==, !=, &&, ^^, ||, +-, forming, units, simulations, ], =, .,}}
void Parser::Parse_NameAdd(SyntaxTreeNode * parent) {

#ifdef TRACE
 CompilerData->LogTrace->ReportEntry("Parse_NameAdd");
#endif

	LexicUnit currentUnit;
	//LexicUnit firstUnit;
	//LexicUnit secondUnit;

	do	{

#ifdef TRACE
  CompilerData->LogTrace->ReportLine("Getting lexic unit.");
#endif

		// get current lexic unit
		currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
		//firstUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition + 1);
		//secondUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition + 2);

		if(currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterPeriod)	{
         /*
			if(firstUnit.type == LUTypeIdentifier && 
				(secondUnit.type == LUTypeSpecialCharacter && secondUnit.subtype == SpecialCharacterLeftParenthesis)
				)
			{
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized epsilon part od production.");
#endif

				// this is epsilon part of production
				// new node is not needed
				// there are no symbols on the right side of this production
				// so that all
				parent->Production = Gr_NameAdd__NamePeriodAdd_NameAdd;
				break;
			}
         */
		
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized Gr_NameAdd__NamePeriodAdd_NameAdd production.");
#endif

			// write type of production in this node
			parent->Production = Gr_NameAdd__NamePeriodAdd_NameAdd;
			// process nonterminal symbol <name_period_add> 
			SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
			parent->Nodes->Add(newNode0);
			Parse_NamePeriodAdd(newNode0);
		}	else if (
			(currentUnit.type == LUTypeSpecialCharacter && 
			((currentUnit.subtype == SpecialCharacterSemicolon) || (currentUnit.subtype == SpecialCharacterLeftCurlyBrace) || 
			(currentUnit.subtype == SpecialCharacterLeftParenthesis) || (currentUnit.subtype == SpecialCharacterColon) || 
			(currentUnit.subtype == SpecialCharacterComma) || (currentUnit.subtype == SpecialCharacterLeftSquareBracket) ||  (currentUnit.subtype == SpecialCharacterRightSquareBracket) || 
			(currentUnit.subtype == SpecialCharacterRightParenthesis) || (currentUnit.subtype == SpecialCharacterPeriod) || 
			(currentUnit.subtype == SpecialCharacterRightSquareBracket) || (currentUnit.subtype == SpecialCharacterPlusOrMinus))) ||
			(currentUnit.type == LUTypeKeyword && 
			((currentUnit.subtype == KeywordAs) || (currentUnit.subtype == KeywordInstance) ||
			(currentUnit.subtype == KeywordAfter) || (currentUnit.subtype == KeywordEvery) || 
			(currentUnit.subtype == KeywordSend) || (currentUnit.subtype == KeywordWhile) ||
			(currentUnit.subtype == KeywordUntil) || (currentUnit.subtype == KeywordForming) ||
			(currentUnit.subtype == KeywordUnits) || (currentUnit.subtype == KeywordSimulations) 
			)) ||
			(currentUnit.type == LUTypeOperator &&
			((currentUnit.subtype == OperatorLessThan) || (currentUnit.subtype == OperatorExponentiation) ||
			(currentUnit.subtype == OperatorMultiplication) || (currentUnit.subtype == OperatorDivision) || 
			(currentUnit.subtype == OperatorModulus) || (currentUnit.subtype == OperatorAddition) ||
			(currentUnit.subtype == OperatorSubtraction) || (currentUnit.subtype == OperatorGreaterThan) ||
			(currentUnit.subtype == OperatorLessThanOrEqualTo) || (currentUnit.subtype == OperatorGreaterThanEqualTo) ||
			(currentUnit.subtype == OperatorEqual) || (currentUnit.subtype == OperatorNotEqual) ||
			(currentUnit.subtype == OperatorAnd) || (currentUnit.subtype == OperatorXor) ||
			(currentUnit.subtype == OperatorOr) || (currentUnit.subtype == OperatorAssigment))) ||
			(currentUnit.type == LUTypeIdentifier)
			)
		{
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized epsilon part od production.");
#endif
			// this is epsilon part of production
			// new node is not needed
			// there are no symbols on the right side of this production
			// so that all
			parent->Production = Gr_NameAdd__NamePeriodAdd_NameAdd;
			break;

		}


		else
		{
#ifdef TRACE
	        CompilerData->LogTrace->ReportLine("Error. Recovery is to skip this lexic unit.");
#endif

			// ERROR has been found
			// REPORT ERROR
			CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_CLASS_BODY_MATCH);
			// MAKE LOGICAL RECOVERING
			this->CurrentLexicPosition++;
			break;
		}
	}
	while(1);

#ifdef TRACE
		CompilerData->LogTrace->ReportExit("Parse_NameAdd");
#endif

}

/*
This method is added just for <variable_value>
*/

// <name_add_ambiguous> ~ <name_period_add> <name_add_ambiguous>  {.}
// <name_add_ambiguous> ~ ? {;, as, {, <, (, :, ,, [, instance, ), NAME, after, every, send, while, until, ^, *, /, %, +, -, >, <=, >=, ==, !=, &&, ^^, ||, +-, forming, units, simulations, ], =, .,}}
void Parser::Parse_NameAdd_Ambiguous(SyntaxTreeNode * parent)
{
#ifdef TRACE
    CompilerData->LogTrace->ReportEntry("Parse_NameAdd_Ambiguous");
#endif
	LexicUnit currentUnit;
	LexicUnit firstUnit;
	LexicUnit secondUnit;

	do
	{
#ifdef TRACE
        CompilerData->LogTrace->ReportLine("Getting lexic unit.");
#endif
		// get current lexic unit
		currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
		firstUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition + 1);
		secondUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition + 2);

		if(currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterPeriod)
		{
         
			if(firstUnit.type == LUTypeIdentifier && 
				(secondUnit.type == LUTypeSpecialCharacter && secondUnit.subtype == SpecialCharacterLeftParenthesis)
				)
			{
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized epsilon part od production.");
#endif

				// this is epsilon part of production
				// new node is not needed
				// there are no symbols on the right side of this production
				// so that all
				parent->Production = Gr_NameAddAmbiguous__NamePeriodAdd_NameAddAmbiguous;
				break;
			}
         
			else
			{
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized Gr_NameAdd__NamePeriodAdd_NameAdd production.");
#endif

				// write type of production in this node
				parent->Production = Gr_NameAddAmbiguous__NamePeriodAdd_NameAddAmbiguous;

				// process nonterminal symbol <name_period_add> 
				SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
				parent->Nodes->Add(newNode0);
				Parse_NamePeriodAdd(newNode0);

		
			}
		}

		else if(
			(currentUnit.type == LUTypeSpecialCharacter && 
			((currentUnit.subtype == SpecialCharacterSemicolon) || (currentUnit.subtype == SpecialCharacterLeftCurlyBrace) || 
			(currentUnit.subtype == SpecialCharacterRightCurlyBrace) ||
			(currentUnit.subtype == SpecialCharacterLeftParenthesis) || (currentUnit.subtype == SpecialCharacterColon) || 
			(currentUnit.subtype == SpecialCharacterComma) || (currentUnit.subtype == SpecialCharacterLeftSquareBracket) ||  (currentUnit.subtype == SpecialCharacterRightSquareBracket) || 
			(currentUnit.subtype == SpecialCharacterRightParenthesis) || (currentUnit.subtype == SpecialCharacterPeriod) || 
			(currentUnit.subtype == SpecialCharacterRightSquareBracket) || (currentUnit.subtype == SpecialCharacterPlusOrMinus))) ||
			(currentUnit.type == LUTypeKeyword && 
			((currentUnit.subtype == KeywordAs) || (currentUnit.subtype == KeywordInstance) ||
			(currentUnit.subtype == KeywordAfter) || (currentUnit.subtype == KeywordEvery) || 
			(currentUnit.subtype == KeywordSend) || (currentUnit.subtype == KeywordWhile) ||
			(currentUnit.subtype == KeywordUntil) || (currentUnit.subtype == KeywordForming) ||
			(currentUnit.subtype == KeywordUnits) || (currentUnit.subtype == KeywordSimulations) 
			)) ||
			(currentUnit.type == LUTypeOperator &&
			((currentUnit.subtype == OperatorLessThan) || (currentUnit.subtype == OperatorExponentiation) ||
			(currentUnit.subtype == OperatorMultiplication) || (currentUnit.subtype == OperatorDivision) || 
			(currentUnit.subtype == OperatorModulus) || (currentUnit.subtype == OperatorAddition) ||
			(currentUnit.subtype == OperatorSubtraction) || (currentUnit.subtype == OperatorGreaterThan) ||
			(currentUnit.subtype == OperatorLessThanOrEqualTo) || (currentUnit.subtype == OperatorGreaterThanEqualTo) ||
			(currentUnit.subtype == OperatorEqual) || (currentUnit.subtype == OperatorNotEqual) ||
			(currentUnit.subtype == OperatorAnd) || (currentUnit.subtype == OperatorXor) ||
			(currentUnit.subtype == OperatorOr) || (currentUnit.subtype == OperatorAssigment))) ||
			(currentUnit.type == LUTypeIdentifier)
			)
		{
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized epsilon part od production.");
#endif
			// this is epsilon part of production
			// new node is not needed
			// there are no symbols on the right side of this production
			// so that all
			parent->Production = Gr_NameAddAmbiguous__NamePeriodAdd_NameAddAmbiguous;
			break;

		}


		else
		{
#ifdef TRACE
	        CompilerData->LogTrace->ReportLine("Error. Recovery is to skip this lexic unit.");
#endif

			// ERROR has been found
			// REPORT ERROR
			CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_CLASS_BODY_MATCH);
			// MAKE LOGICAL RECOVERING
			this->CurrentLexicPosition++;
			break;
		}
	}
	while(1);

#ifdef TRACE
		CompilerData->LogTrace->ReportExit("Parse_NameAdd_Ambiguous");
#endif

}

// <name_period_add> ~ . NAME  {.}
void Parser::Parse_NamePeriodAdd(SyntaxTreeNode * parent) {

#ifdef TRACE
 CompilerData->LogTrace->ReportEntry("Parse_NamePeriodAdd");
#endif

	LexicUnit currentUnit;

#ifdef TRACE
	CompilerData->LogTrace->ReportLine("Getting lexic unit.");
#endif

	// get current lexic unit
	currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
	if(currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterPeriod)	{

#ifdef TRACE
		CompilerData->LogTrace->ReportLine("Recognized special character \".\"");
#endif

		// write type of production in this node
		parent->Production = Gr_NamePeriodAdd__spPer_NAME;
		// process terminal symbol '.' 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		newNode0->LexUnitID=this->CurrentLexicPosition;
		newNode0->Production=Gr_Terminal;
		//increase counter
		CurrentLexicPosition++;
		// process terminal symbol 'NAME' 
		currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
		if(currentUnit.type == LUTypeIdentifier)	{

#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized identifier.");
#endif
			SyntaxTreeNode * newNode1 = new SyntaxTreeNode();
			parent->Nodes->Add(newNode1);
			newNode1->LexUnitID=this->CurrentLexicPosition;
			newNode1->Production=Gr_Terminal;
			//increase counter
			CurrentLexicPosition++;
		}
		else
		{
			//report syntactic error
			//increase counter
			CurrentLexicPosition++;
		}

	}


	else
	{
#ifdef TRACE
	        CompilerData->LogTrace->ReportLine("Error.");
#endif
		// ERROR has been found
		// REPORT ERROR
		CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_CLASS_BODY_MATCH);
		// MAKE LOGICAL RECOVERING
	}
#ifdef TRACE
	CompilerData->LogTrace->ReportExit("Parse_NamePeriodAdd");
#endif

}


// <array_definitions_size> ~ <array_definition_size> <array_definitions_size>  {[}
// <array_definitions_size> ~ ? {:,(, {, ^, *, /, %, +, -, <, >, <=, >=, ==, !=, &&, ^^, ||, ,, ;, ), +-, forming, units, simulations, ], NAME, after, every, send, while, until, =, .,}}
void Parser::Parse_ArrayDefinitionsSize(SyntaxTreeNode * parent)
{
#ifdef TRACE
       CompilerData->LogTrace->ReportEntry("Parse_ArrayDefinitionsSize");
#endif
	LexicUnit currentUnit;
	do
	{
#ifdef TRACE
	CompilerData->LogTrace->ReportLine("Getting lexic unit.");
#endif
		// get current lexic unit
		currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);

		if(currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterLeftSquareBracket)
		{
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized special character \"[\"");
#endif

			// write type of production in this node
			parent->Production = Gr_ArrayDefinitionsSize__ArrayDefinitionSize_ArrayDefinitionsSize;

			// process nonterminal symbol <array_definition_size> 
			SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
			parent->Nodes->Add(newNode0);
			Parse_ArrayDefinitionSize(newNode0);

		}

		else if(
			(currentUnit.type == LUTypeSpecialCharacter && 
			((currentUnit.subtype == SpecialCharacterLeftParenthesis) || (currentUnit.subtype == SpecialCharacterLeftCurlyBrace) ||
			(currentUnit.subtype == SpecialCharacterRightCurlyBrace) ||
			(currentUnit.subtype == SpecialCharacterPeriod) || (currentUnit.subtype == SpecialCharacterComma) || (currentUnit.subtype == SpecialCharacterColon) ||
			(currentUnit.subtype == SpecialCharacterSemicolon) || (currentUnit.subtype == SpecialCharacterRightParenthesis) ||
			(currentUnit.subtype == SpecialCharacterPlusOrMinus) || (currentUnit.subtype == SpecialCharacterRightSquareBracket))) ||
			(currentUnit.type == LUTypeOperator && 
			((currentUnit.subtype == OperatorExponentiation) || (currentUnit.subtype == OperatorMultiplication) ||
			(currentUnit.subtype == OperatorDivision) || (currentUnit.subtype == OperatorModulus) ||
			(currentUnit.subtype == OperatorAddition) || (currentUnit.subtype == OperatorSubtraction) ||
			(currentUnit.subtype == OperatorLessThan) || (currentUnit.subtype == OperatorGreaterThan) ||
			(currentUnit.subtype == OperatorLessThanOrEqualTo) || (currentUnit.subtype == OperatorGreaterThanEqualTo) ||
			(currentUnit.subtype == OperatorEqual) || (currentUnit.subtype == OperatorNotEqual) ||
			(currentUnit.subtype == OperatorAnd) || (currentUnit.subtype == OperatorXor) ||
			(currentUnit.subtype == OperatorOr) || (currentUnit.subtype == OperatorAssigment))) ||
			(currentUnit.type == LUTypeKeyword &&
			((currentUnit.subtype == KeywordForming) || (currentUnit.subtype == KeywordUnits) || 
			(currentUnit.subtype == KeywordSimulations) || (currentUnit.subtype == KeywordAfter) || 
			(currentUnit.subtype == KeywordEvery) || (currentUnit.subtype == KeywordSend) || 
			 (currentUnit.subtype == KeywordWhile) || 
			(currentUnit.subtype == KeywordUntil)))||
			(currentUnit.type == LUTypeIdentifier))
		{
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized epsilon production.");
#endif

			// this is epsilon part of production
			// new node is not needed
			// there are no symbols on the right side of this production
			// so that all
			parent->Production = Gr_ArrayDefinitionsSize__ArrayDefinitionSize_ArrayDefinitionsSize;
			break;

		}


		else
		{
#ifdef TRACE
	        CompilerData->LogTrace->ReportLine("Error. Recovery is to skip this lexic unit.");
#endif
			// ERROR has been found
			// REPORT ERROR
			CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_CLASS_BODY_MATCH);
			// MAKE LOGICAL RECOVERING
			this->CurrentLexicPosition++;
			break;
		}
	}
	while(1);
#ifdef TRACE
	CompilerData->LogTrace->ReportExit("Parse_ArrayDefinitionsSize");
#endif
}



// <array_definition_size> ~ [ <expression> ]  {[}
void Parser::Parse_ArrayDefinitionSize(SyntaxTreeNode * parent)
{
#ifdef TRACE
       CompilerData->LogTrace->ReportEntry("Parse_ArrayDefinitionSize");
#endif

	LexicUnit currentUnit;
#ifdef TRACE
	CompilerData->LogTrace->ReportLine("Getting lexic unit.");
#endif
	// get current lexic unit
	currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);

	if(currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterLeftSquareBracket)
	{
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized special character \"[\"");
#endif
		// write type of production in this node
		parent->Production = Gr_ArrayDefinitionSize__spLSBrac_Expression_spRSBrac;

		// process terminal symbol '[' 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		newNode0->LexUnitID=this->CurrentLexicPosition;
		newNode0->Production=Gr_Terminal;
		//increase counter
		CurrentLexicPosition++;

		// process nonterminal symbol <expression> 
		SyntaxTreeNode * newNode1 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode1);
		Parse_Expression(newNode1);

		// process terminal symbol ']' 
		currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
		if(currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterRightSquareBracket)
		{
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Recognized special character \"]\"");
#endif
			SyntaxTreeNode * newNode2 = new SyntaxTreeNode();
			parent->Nodes->Add(newNode2);
			newNode2->LexUnitID=this->CurrentLexicPosition;
			newNode2->Production=Gr_Terminal;
			//increase counter
			CurrentLexicPosition++;
		}
		else
		{
			//report syntactic error
			//increase counter
			CurrentLexicPosition++;
		}

	}


	else
	{
#ifdef TRACE
	        CompilerData->LogTrace->ReportLine("Error.");
#endif
		// ERROR has been found
		// REPORT ERROR
		CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_CLASS_BODY_MATCH);
		// MAKE LOGICAL RECOVERING
	}
#ifdef TRACE
	CompilerData->LogTrace->ReportExit("Parse_ArrayDefinitionSize");
#endif

}

